﻿/// <reference path="jquery.d.ts" />
/// <reference path="backbone.d.ts" />
/// <reference path="datepicker.d.ts" />
/// <reference path="spiro-models.ts" />
/// <reference path="spiro-models-helpers.ts" />
/// <reference path="tags.ts" />


declare var _: any;

module Spiro.Narrow {

    function displayOnMain(): JQuery {
        $("#main").html("");
        return $("#main");
    };

    function renderOnMain(view: Backbone.View, content: string) {
        view.$el.html(content);
        displayOnMain().html(view.$el);
        return view;
    }

    var home: Spiro.HomePageRepresentation;

    class OrderPage extends Backbone.View {
        constructor (public model: Spiro.DomainObjectRepresentation, options? ) {
            super(options);
            _.bindAll(this, 'render');
            this.model.bind('change', this.render);
            this.model.bind('reset', this.render);

            // why do we need this - shouldn't do - need to check 
            this.delegateEvents();
        }

        renderOrder(): string {
            var order = this.model;

            var acnTag = Tags.Tag("p", "", "Order no: " + order.propertyMembers()["SalesOrderNumber"].value());
            var cTag = Tags.Tag("p", "", "Customer: " + order.propertyMembers()["Customer"].value());
            var aTag = Tags.Tag("p", "", "Amount: " + order.propertyMembers()["TotalDue"].value());

            return acnTag.toString() + cTag + aTag;
        }

        render(): OrderPage {
            return <OrderPage> renderOnMain(this, this.renderOrder());
        }
    }


    class ConfirmOrderPage extends Backbone.View {
        constructor (public model: Spiro.DomainObjectRepresentation, options? ) {
            super(options);
            _.bindAll(this, 'render', 'onOK');
            this.model.bind('change', this.render);
            this.model.bind('reset', this.render);

            // why do we need this - shouldn't do - need to check 
            this.delegateEvents();
        }

        product: Link;
        count: number;

        events = {
            "click :button": "onOK",
        }

        onOK(e: JQueryEventObject) {

            var invoke = Helpers.createActionInvoke(this.model, "CreateNewOrder");
          
            Helpers.invoke(invoke, {"copyHeaderFromLastOrder": true}, {
                "success": (originalModel, resp, iOptions) => {

                    var order = invoke.result().object();
                 
                    var members = {
                        "SalesOrderNumber": "placeholder",
                        "CreditCardApprovalCode": "placeholder"
                    };

                    Helpers.persist(order, members, {
                        "success": (originalModel, resp, iOptions) => {
                            // now update with products 

                            var innerInvoke = Helpers.createActionInvoke(order, "AddNewDetail");

                            var parameters = {
                                "product": this.product,
                                "quantity": this.count
                            }


                            Helpers.invoke(innerInvoke, parameters, {
                                "success": (originalModel, resp, iOptions) => {

                                    var orderLine = innerInvoke.result().object();

                                    Helpers.persist(orderLine, {}, {
                                        "success": (originalModel, resp, iOptions) => {
                                            var op = new OrderPage(order);
                                            order.fetch();
                                        },
                                        "error": (originalModel, resp, iOptions) => {
                                            renderOnMain(this, "failed to save order detail " + resp.message);
                                        }
                                    });
                                },
                                "error": (originalModel, resp, iOptions) => {
                                    renderOnMain(this, "failed to add order detail " + resp.message);
                                }
                            })
                        },
                        "error": (originalModel, resp, iOptions) => {
                            renderOnMain(this, "failed to persist new order " + resp.message);
                        }
                    });
                },
                "error": (originalModel, resp, iOptions) => {
                    renderOnMain(this, "failed to create new order "  + resp.message);
                }
            });

            return false;
        }

        renderOrderSummary(): string {

            var summaryTag = Tags.Tag("p", "", "Create Order : ");
            var productTag = Tags.Tag("p", "", "Selected " + this.count + "  " + this.product.title());
            var customerTag = Tags.Tag("p", "", "Customer: " + this.model.title());
            var buttontag = Tags.Tag("button", "", "OK");

            return summaryTag.toString() + productTag + customerTag + buttontag;
        }

        render(): ConfirmOrderPage {
            return <ConfirmOrderPage> renderOnMain(this, this.renderOrderSummary());
        }

    }


    class ChooseCustomerPage extends Backbone.View {
        constructor (options?) {
            super(options);

            this.model = new Spiro.ActionResultRepresentation();

            this.model.hateoasUrl = "http://mvc.nakedobjects.net:1081/RestDemo/services/AdventureWorksModel.CustomerRepository/actions/FindStoreByName/invoke";
            this.model.method = "GET"

            _.bindAll(this, 'render', 'reRender',  'onOK');
            this.model.bind('change', this.reRender);
            this.model.bind('reset', this.reRender);
            this.model.bind('requestFailed', this.reRender);

            // why do we need this - shouldn't do - need to check 
            this.delegateEvents();
        }

        model: ActionResultRepresentation;

        result: ListRepresentation;
        product: Link;
        count: number;

        events = {
            "click :button": "onOK",
        }

        onOK(e: JQueryEventObject) {
            // create a new order for the selected customer

            var customerLink = this.result.value().models[$("select").val()];

            var customer = <DomainObjectRepresentation> customerLink.getTarget();

            var cPage = new ConfirmOrderPage(customer);

            cPage.product = this.product;
            cPage.count = this.count;

            customer.fetch();

            return false;
        }

        searchValue; 
        
        search() { 
            Helpers.invoke(this.model, { "name": this.searchValue });
        }

        reRender() {
            this.result = this.model.result().list();
            var select = this.$el.find("select")
            select.html(""); 

            for (var i = 0;  this.result && i < this.result.value().models.length; i++) {
                var title = this.result.value().models[i].title();
                var optionTag = Tags.Tag("option", "", title)
                optionTag.mergeAttribute("value", i.toString());
                select.append(optionTag.toString()); 
            }
        }


        renderCustomerSelection(): string {

            var page = Tags.Tag("div", "");

            var products = Tags.Tag("p", "", "Selected " + this.count + "  " + this.product.title());

            page.innerHtml += products;

            page.innerHtml += Tags.Tag("input", "customerSearch");

            var ddTag = Tags.Tag("select", "");

            var buttonTag = Tags.Tag("button", "okButton", "OK");

            page.innerHtml += ddTag;
            page.innerHtml += buttonTag;

            return page.toString();
        }


        render(): ChooseCustomerPage {
            var p  =  <ChooseCustomerPage> renderOnMain(this, this.renderCustomerSelection());

            var view = this;

            this.$el.find(".customerSearch").bind("propertychange keyup input paste", function (event) {
                view.searchValue = $(this).val();
                view.search();
            });

            return p;

        }

    }

    class ChooseProductPage extends Backbone.View {

        constructor (options?) {
            super(options);
            this.model = Helpers.createUrlInvoke("http://mvc.nakedobjects.net:1081/RestDemo/services/AdventureWorksModel.ProductRepository/actions/FindProductByName/invoke", "GET");
  
            _.bindAll(this, 'render', 'reRender', 'onOK');
            this.model.bind('change', this.reRender);
            this.model.bind('reset', this.reRender);
            this.model.bind('requestFailed', this.reRender);

            // why do we need this - shouldn't do - need to check 
            this.delegateEvents();
        }

        model: ActionResultRepresentation; 

        result: ListRepresentation;

        searchValue = ""; 

        events = {
            "click :button": "onOK",
        }

        onOK(e: JQueryEventObject) {
            var ccView = new ChooseCustomerPage();

            ccView.product = this.result.value().models[$("select").val()];
            ccView.count = $("input.productCount").val();

            ccView.render();
            return false;
        }

        search() {         
            Helpers.invoke(this.model, {"searchString": this.searchValue}); 
        }

        renderProductSelection(): string {
            var page = Tags.Tag("div", "");

            page.innerHtml += Tags.Tag("input", "productSearch");
            page.innerHtml += Tags.Tag("select", "");

            var countTag = Tags.Tag("input", "productCount");
            countTag.mergeAttribute("value", "1");

            page.innerHtml += countTag;
            page.innerHtml += Tags.Tag("button", "okButton", "OK");

            return page.toString();
        }

        reRender() {
            this.result =  this.model.result().list();
            var select = this.$el.find("select")
            select.html(""); 

            for (var i = 0;  (this.result) && i < this.result.value().models.length; i++) {
                var title = this.result.value().models[i].title();
                var optionTag = Tags.Tag("option", "", title)
                optionTag.mergeAttribute("value", i.toString());
                select.append(optionTag.toString()); 
            }
        }

        render(): ChooseProductPage {
            var p = <ChooseProductPage> renderOnMain(this, this.renderProductSelection());
            var view = this;

            this.$el.find(".productSearch").bind("propertychange keyup input paste", function (event) {
                view.searchValue = $(this).val();
                view.search();
            });

            return p;
        }

    }

    class AppRouter extends Backbone.Router {

        constructor (options) {
            super(options);
        }

        home() {
            new ChooseProductPage().render();
        }
    }

    var app = new AppRouter({ "routes": { "": "home" } });

    Backbone.history.start();

    window.onerror = function (msg, url, linenumber) {
        alert('Error message: ' + msg + '\nURL: ' + url + '\nLine Number: ' + linenumber);
        return true;
    };

    var bindAjaxError = function () {
        $("div#main").ajaxError(function (e, xhr, settings) {
            //  errorDialog('Ajax Error', "Error in: " + settings.url + " \n" + "error:\n" + xhr.responseText);

            alert('ajax error');
        });
    };
}